package feign.hystrix;

/**
 * @ClassName HystrixInvocationHandler
 * @description
 * @Author zhouj
 * @Date 2021/11/2 10:11
 */
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//


import com.koron.common.core.feignConfig.ExtFallbackFactory;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommand.Setter;
import feign.InvocationHandlerFactory.MethodHandler;
import feign.Target;
import feign.Util;
import rx.Completable;
import rx.Observable;
import rx.Single;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

final class HystrixInvocationHandler implements InvocationHandler {
    private final Target<?> target;
    private final Map<Method, MethodHandler> dispatch;
    private final FallbackFactory<?> fallbackFactory;
    private final Map<Method, Method> fallbackMethodMap;
    private final Map<Method, Setter> setterMethodMap;

    HystrixInvocationHandler(Target<?> target, Map<Method, MethodHandler> dispatch, SetterFactory setterFactory, FallbackFactory<?> fallbackFactory) {
        this.target = (Target) Util.checkNotNull(target, "target", new Object[0]);
        this.dispatch = (Map) Util.checkNotNull(dispatch, "dispatch", new Object[0]);
        this.fallbackFactory = fallbackFactory;
        this.fallbackMethodMap = toFallbackMethod(dispatch);
        this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet());
    }

    static Map<Method, Method> toFallbackMethod(Map<Method, MethodHandler> dispatch) {
        Map<Method, Method> result = new LinkedHashMap();
        Iterator var2 = dispatch.keySet().iterator();

        while (var2.hasNext()) {
            Method method = (Method) var2.next();
            method.setAccessible(true);
            result.put(method, method);
        }

        return result;
    }

    static Map<Method, Setter> toSetters(SetterFactory setterFactory, Target<?> target, Set<Method> methods) {
        Map<Method, Setter> result = new LinkedHashMap();
        Iterator var4 = methods.iterator();

        while (var4.hasNext()) {
            Method method = (Method) var4.next();
            method.setAccessible(true);
            result.put(method, setterFactory.create(target, method));
        }

        return result;
    }

    public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
        if (!"equals".equals(method.getName())) {
            if ("hashCode".equals(method.getName())) {
                return this.hashCode();
            } else if ("toString".equals(method.getName())) {
                return this.toString();
            } else {
                HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>((Setter) this.setterMethodMap.get(method)) {
                    protected Object run() throws Exception {
                        try {
                            return ((MethodHandler) HystrixInvocationHandler.this.dispatch.get(method)).invoke(args);
                        } catch (Exception var2) {
                            throw var2;
                        } catch (Throwable var3) {
                            throw (Error) var3;
                        }
                    }

                    protected Object getFallback() {
                        if (HystrixInvocationHandler.this.fallbackFactory == null) {
                            return super.getFallback();
                        } else {
                            try {
                                //Object fallback = HystrixInvocationHandler.this.fallbackFactory.create(this.getExecutionException());
                                //注释掉原有的
                                //Object fallback = ((ExtFallbackFactory)fallbackFactory).create(getExecutionException());
                                //这里改成我们自己的
                                Object fallback = ((ExtFallbackFactory) fallbackFactory).create(method, getExecutionException());
                                Object result = ((Method) HystrixInvocationHandler.this.fallbackMethodMap.get(method)).invoke(fallback, args);
                                if (HystrixInvocationHandler.this.isReturnsHystrixCommand(method)) {
                                    return ((HystrixCommand) result).execute();
                                } else if (HystrixInvocationHandler.this.isReturnsObservable(method)) {
                                    return ((Observable) result).toBlocking().first();
                                } else if (HystrixInvocationHandler.this.isReturnsSingle(method)) {
                                    return ((Single) result).toObservable().toBlocking().first();
                                } else if (HystrixInvocationHandler.this.isReturnsCompletable(method)) {
                                    ((Completable) result).await();
                                    return null;
                                } else {
                                    return HystrixInvocationHandler.this.isReturnsCompletableFuture(method) ? ((Future) result).get() : result;
                                }
                            } catch (IllegalAccessException var3) {
                                throw new AssertionError(var3);
                            } catch (ExecutionException | InvocationTargetException var4) {
                                throw new AssertionError(var4.getCause());
                            } catch (InterruptedException var5) {
                                Thread.currentThread().interrupt();
                                throw new AssertionError(var5.getCause());
                            }
                        }
                    }
                };
                if (Util.isDefault(method)) {
                    return hystrixCommand.execute();
                } else if (this.isReturnsHystrixCommand(method)) {
                    return hystrixCommand;
                } else if (this.isReturnsObservable(method)) {
                    return hystrixCommand.toObservable();
                } else if (this.isReturnsSingle(method)) {
                    return hystrixCommand.toObservable().toSingle();
                } else if (this.isReturnsCompletable(method)) {
                    return hystrixCommand.toObservable().toCompletable();
                } else {
                    return this.isReturnsCompletableFuture(method) ? new ObservableCompletableFuture(hystrixCommand) : hystrixCommand.execute();
                }
            }
        } else {
            try {
                Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                return this.equals(otherHandler);
            } catch (IllegalArgumentException var5) {
                return false;
            }
        }
    }

    private boolean isReturnsCompletable(Method method) {
        return Completable.class.isAssignableFrom(method.getReturnType());
    }

    private boolean isReturnsHystrixCommand(Method method) {
        return HystrixCommand.class.isAssignableFrom(method.getReturnType());
    }

    private boolean isReturnsObservable(Method method) {
        return Observable.class.isAssignableFrom(method.getReturnType());
    }

    private boolean isReturnsCompletableFuture(Method method) {
        return CompletableFuture.class.isAssignableFrom(method.getReturnType());
    }

    private boolean isReturnsSingle(Method method) {
        return Single.class.isAssignableFrom(method.getReturnType());
    }

    public boolean equals(Object obj) {
        if (obj instanceof HystrixInvocationHandler) {
            HystrixInvocationHandler other = (HystrixInvocationHandler) obj;
            return this.target.equals(other.target);
        } else {
            return false;
        }
    }

    public int hashCode() {
        return this.target.hashCode();
    }

    public String toString() {
        return this.target.toString();
    }
}

